function() to create a function object<function_name> <- function(<arg_1>, <arg_2>, ..., <arg_n>) {
<function_body>
}
foo <- function(arg) {
# <function_body>
}
body()) - code inside the functionformals()) - controls how function is calledenvironment()) - location of function's definition and variablesis_positive <- function(num) {
if (num > 0) {
return(TRUE)
} else {
return(FALSE)
}
}
body(is_positive)
{
if (num > 0) {
return(TRUE)
}
else {
return(FALSE)
}
}
formals(is_positive)
$num
environment(is_positive)
<environment: R_GlobalEnv>
return() function is encounteredreturn() function callreturn() (implicit return)is_positive <- function(num) {
if (num > 0) {
res <- TRUE
} else {
res <- FALSE
}
return(res)
}
res_1 <- is_positive(5)
res_2 <- is_positive(-7)
print(res_1)
print(res_2)
[1] TRUE [1] FALSE
is_positive <- function(num) {
if (num > 0) {
res <- TRUE
} else {
res <- FALSE
}
res
}
res_1 <- is_positive(5)
res_2 <- is_positive(-7)
print(res_1)
print(res_2)
[1] TRUE [1] FALSE
# While this function provides the same functionality as the two versions above
# This is an example of a bad programming style, return value is very unintuitive
is_positive <- function(num) {
if (num > 0) {
res <- TRUE
} else {
res <- FALSE
}
}
res_1 <- is_positive(5)
res_2 <- is_positive(-7)
print(res_1)
print(res_2)
[1] TRUE [1] FALSE
format_date <- function(day, month, year, reverse = TRUE) {
if (isTRUE(reverse)) {
formatted <- paste(
as.character(year), as.character(month), as.character(day), sep = "-"
)
} else {
formatted <- paste(
as.character(day), as.character(month), as.character(year), sep = "-"
)
}
return(formatted)
}
format_date(4, 10, 2021)
[1] "2021-10-4"
format_date(y = 2021, m = 10, d = 4) # Technically correct, but rather unintuitive
[1] "2021-10-4"
format_date(y = 2021, m = 10, d = 4, FALSE) # Technically correct, but rather unintuitive
[1] "4-10-2021"
format_date(day = 4, month = 10, year = 2021, FALSE)
[1] "4-10-2021"
which_integer <- function(num) {
even_or_odd <- function(num) {
if (num %% 2 == 0) {
return("even")
} else {
return("odd")
}
}
eo <- even_or_odd(num)
if (num > 0) {
return(paste0("positive ", eo))
} else if (num < 0) {
return(paste0("negative ", eo))
} else {
return("zero")
}
}
which_integer(-43)
[1] "negative odd"
even_or_odd(-43)
Error in even_or_odd(-43): could not find function "even_or_odd" Traceback:
x <- 42
# is equivalent to:
# Binding R object '42', double vector of length 1, to name 'x' in the global environment
assign("x", 42, envir = .GlobalEnv)
x
[1] 42
x <- 5
foo <- function() {
x <- 12
return(x)
}
y <- foo()
print(y)
print(x)
[1] 12 [1] 5
`+`(3, 2) # Equivalent to: 3 + 2
[1] 5
`<-`(x, c(10, 12, 14)) # x <- c(10, 12, 14)
x
[1] 10 12 14
`[`(x, 3) # x[3]
[1] 14
`>`(x, 10) # x > 10
[1] FALSE TRUE TRUE
function() does not have to be assigned to a variablefunction() can be easily incorporate into other function callsadd_five <- function() {
return(function(x) x + 5)
}
af <- add_five()
af # 'af' is just a function, which is yet to be invoked (called)
function(x) x + 5 <environment: 0x55d78232a7d8>
af(10) # Here we call a function and supply 10 as an argument
[1] 15
# Due to vectorized functions in R this example is an obvious overkill (seq(10) ^ 2 would do just fine)
# but it shows a general approach when we might need to apply a non-vectorized functions
sapply(seq(10), function(x) x ^ 2)
[1] 1 4 9 16 25 36 49 64 81 100
apply() family of base R functionals is the most ubiquitous example# Applies a supplied function to a random draw
# from the normal distribution with mean 0 and sd 1
functional <- function(f) { f(rnorm(10)) }
functional(mean)
[1] -0.09413735
functional(median)
[1] -0.1556706
functional(sum)
[1] -2.926588
apply() functions¶| Function | Description | Input Object | Output Object | Simplified |
|---|---|---|---|---|
apply() |
Apply a given function to margins (rows/columns) of input object | matrix/array/data.frame | vector/matrix/array/list | Yes |
lapply() |
Apply a given function to each element of input object | vector/list | list | No |
sapply() |
Same as lapply(), but output is simplified |
vector/list | vector/matrix | Yes |
vapply() |
Same as sapply(), but data type of output is specified |
vector/list | vector | No |
mapply() |
Multivariate version of sapply(), takes multiple objects as input |
vectors/lists | vector/matrix | Yes |
lapply() function¶lapply(<input_object>, <function_name>, <arg_1>, ..., <arg_n>)
lapply() examples¶l <- list(a = 1:2, b = 3:4, c = 5:6, d = 7:8, e = 9:10)
# Apply sum() to each element of list 'l'
lapply(l, sum)
$a [1] 3 $b [1] 7 $c [1] 11 $d [1] 15 $e [1] 19
# We can exploit the fact that basic operators are function calls
# Here, each subsetting operator `[` with argument 2 is applied to each element
# Which gives us second element within each element of the list
lapply(l, `[`, 2)
$a [1] 2 $b [1] 4 $c [1] 6 $d [1] 8 $e [1] 10
apply() function¶<margin> argument indicates whether function is applied across rows (1) or columns (2)apply(<input_object>, <margin>, <function_name>, <arg_1>, ..., <arg_n>)
apply() examples¶m <- matrix(1:12, nrow = 3, ncol = 4)
m
[,1] [,2] [,3] [,4] [1,] 1 4 7 10 [2,] 2 5 8 11 [3,] 3 6 9 12
# Sum up rows (can also be achieved with rowSums() function)
apply(m, 1, sum)
[1] 22 26 30
# Calculate averages across columns (also available in colMeans())
apply(m, 2, mean)
[1] 2 5 8 11
# Find maximum value in each column
apply(m, 2, max)
[1] 3 6 9 12
mapply() function¶mapply(<function_name>, <input_object_1>, ..., <input_object_n>, <arg_1>, ..., <arg_n>)
mapply() examples¶means <- -2:2
sds <- 1:5
# Generate one draw from a normal distribution where
# each mean is an element of vector 'means'
# and each standard deivation is an element of vector 'sds'
#
# rnorm(n, mean, sd) takes 3 arguments: n, mean, sd
mapply(rnorm, 1, means, sds)
[1] -2.3877425 -3.8041251 1.2425808 4.2079390 0.2520243
# While simplification of output
# (attempt to collapse it in fewer dimensions)
# makes hard to predict the object returned
# by apply() functions that have simplified = TRUE by default
mapply(rnorm, 5, means, sds)
[,1] [,2] [,3] [,4] [,5] [1,] -1.676801 -3.0455835 0.8957769 0.5118888 -6.4469782 [2,] -2.690624 -1.5524074 -1.4870650 -4.4084040 2.4245422 [3,] -1.664708 -0.9970396 0.9591408 -1.7019869 0.7672098 [4,] -1.400437 -1.9529977 1.0721986 -0.2210901 8.5994742 [5,] -1.958179 2.6664414 0.4189656 -1.5375013 8.7470140
library() function::)library(<package_name>)
<package_name>::<object_name>
# Package 'Matrix' is part of the standard R library and doesn't have to be installed separately
library("Matrix")
Warning message: “package ‘Matrix’ was built under R version 4.1.3”
# While it is possible to just use function sparseVector() after loading the library,
# it is good practice to state explicitly which package the object is coming from.
sv <- Matrix::sparseVector(x = c(1, 2, 3), i = c(3, 6, 9), length = 10)
sv
sparse vector (nnz/length = 3/10) of class "dsparseVector" [1] . . 1 . . 2 . . 3 .